
# 从qtpy库的QtWidgets模块导入所有类
from qtpy.QtWidgets import *
# 从qtpy库导入QtCore和QtGui模块
from qtpy import QtCore, QtGui


class KeyCaptureWidget(QPushButton):
    """
    KeyCaptureWidget类继承自QPushButton，用于捕获键盘按键。
    当用户点击按钮开始捕获按键，捕获到有效按键后会发出信号。

    :ivar captured: 自定义信号，当捕获到按键时发射，携带捕获到的按键信息。
    """

    # 定义一个信号，当捕获到按键时发射，携带按键信息
    captured = QtCore.Signal(object)

    def __init__(self, parent=None):
        """
        初始化KeyCaptureWidget实例。

        :param parent: 父控件，默认为None。
        """
        # 调用父类QPushButton的构造函数
        super(KeyCaptureWidget, self).__init__(parent)
        # 标记是否正在捕获按键
        self.bCapturing = False
        # 存储当前捕获到的按键
        self._currentKey = None
        # 设置按钮的初始文本为 "NoKey"
        self.setText("NoKey")
        # 设置按钮为可勾选状态
        self.setCheckable(True)
        # 设置按钮的提示信息，告知用户操作方式
        self.setToolTip(
            "<b>Left mouse button</b> to start capture.<br>Modifiers will not be accepted."
        )

        # 设置上下文菜单策略，此处存在类 'Qt' 的未解析的特性引用问题
        self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
        # 创建一个名为 "Reset" 的动作
        self.actionReset = QAction("Reset", None)
        # 连接动作的触发信号到resetToDefault方法
        self.actionReset.triggered.connect(self.resetToDefault)
        # 将动作添加到按钮的上下文菜单中
        self.addAction(self.actionReset)

    def resetToDefault(self):
        """
        将按钮重置为默认状态，停止捕获按键，清除当前按键信息。
        """
        # 取消按钮的勾选状态
        self.setChecked(False)
        # 停止捕获按键
        self.bCapturing = False
        # 清除当前捕获到的按键
        self.currentKey = None

    @property
    def currentKey(self):
        """
        获取当前捕获到的按键。

        :return: 当前捕获到的按键，若没有则为None。
        """
        return self._currentKey

    @currentKey.setter
    def currentKey(self, value):
        """
        设置当前捕获到的按键，并更新按钮文本，发射捕获信号。

        :param value: 要设置的按键，若为None则重置按钮状态。
        """
        if value is None:
            # 若传入None，设置按钮文本为 "NoKey"，停止捕获并取消勾选
            self.setText("NoKey")
            self.bCapturing = False
            self.setChecked(False)
        else:
            # 存储传入的按键
            self._currentKey = value
            # 将按键转换为字符串并设置为按钮文本
            self.setText(QtGui.QKeySequence(self._currentKey).toString())
            # 停止捕获并取消勾选
            self.bCapturing = False
            self.setChecked(False)
            # 发射捕获信号，携带捕获到的按键信息
            self.captured.emit(self._currentKey)

    def mousePressEvent(self, event):
        """
        处理鼠标按下事件，当左键点击且未在捕获时，开始捕获按键。

        :param event: 鼠标事件对象。
        """
        # 调用父类的鼠标按下事件处理方法
        super(KeyCaptureWidget, self).mousePressEvent(event)
        # 检查是否为左键点击且未在捕获按键
        if event.button() == QtCore.Qt.MouseButton.LeftButton and not self.bCapturing:
            if not self.bCapturing:
                # 开始捕获按键
                self.bCapturing = True
                # 设置按钮文本为 "capturing..."
                self.setText("capturing...")

    def keyPressEvent(self, event):
        """
        处理键盘按键事件，根据修饰键情况决定是否捕获按键。

        :param event: 键盘事件对象。
        """
        # 调用父类的键盘按键事件处理方法
        super(KeyCaptureWidget, self).keyPressEvent(event)
        # 获取按下的按键
        key = event.key()
        # 获取按下按键时的修饰键，此处存在类 'Qt' 的未解析的特性引用问题
        modifiers = event.modifiers()
        # 检查是否没有按下修饰键
        if modifiers == QtCore.Qt.NoModifier:
            # 若没有修饰键，设置当前捕获到的按键
            self.currentKey = QtCore.Qt.Key(key)
        # 检查是否按下了修饰键
        if not modifiers == QtCore.Qt.NoModifier:
            # 若按下修饰键，重置按钮为默认状态
            self.resetToDefault()


if __name__ == "__main__":
    import sys

    # 创建一个QApplication实例
    a = QApplication(sys.argv)

    # 创建KeyCaptureWidget实例
    w = KeyCaptureWidget()
    # 显示窗口
    w.show()

    # 进入应用程序的事件循环，等待用户操作
    sys.exit(a.exec_())